package com.neusoft.neuiotms.dcom.service.impl;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.persistence.EntityNotFoundException;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.dcom.constants.DCOMConstants;
import com.neusoft.neuiotms.dcom.converter.StopServiceNoticeConverter;
import com.neusoft.neuiotms.dcom.dto.CMDBInstanceDTO;
import com.neusoft.neuiotms.dcom.dto.StopServiceNoticeDTO;
import com.neusoft.neuiotms.dcom.dto.UserDTO;
import com.neusoft.neuiotms.dcom.model.StopServiceNotice;
import com.neusoft.neuiotms.dcom.model.enums.StopServiceNoticeSendStatusEnum;
import com.neusoft.neuiotms.dcom.repository.StopServiceNoticeRepository;
import com.neusoft.neuiotms.dcom.service.StopServiceNoticeService;
import com.neusoft.neuiotms.dcom.util.SendingMessageDcom;

import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class StopServiceNoticeServiceImpl implements StopServiceNoticeService {

    @Autowired
    private StopServiceNoticeRepository stopServiceNoticeRepository;

    @Autowired
    private StopServiceNoticeConverter stopServiceNoticeConventer;

    @Autowired
    private SendingMessageDcom sendingMessage;

    @Override
    public List<StopServiceNoticeDTO> findAll() {
        final List<StopServiceNotice> entity = this.stopServiceNoticeRepository.findAll();
        final List<StopServiceNoticeDTO> dtos =
                this.stopServiceNoticeConventer.toListDTO(entity);
        return dtos;
    }

    @Override
    public Page<StopServiceNoticeDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<StopServiceNotice> models = this.stopServiceNoticeRepository.search(pageable, searchable);
        return this.stopServiceNoticeConventer.toPageDTO(models);
    }

    @Override
    public StopServiceNoticeDTO create(final StopServiceNoticeDTO dto) {
        final StopServiceNotice model = this.stopServiceNoticeConventer.toModel(dto);

        this.stopServiceNoticeRepository.save(model);

        this.asyncSendMessage(model);

        return this.stopServiceNoticeConventer.toDTO(model);
    }

    @Override
    public StopServiceNoticeDTO update(final Long id, final StopServiceNoticeDTO dto) {
        StopServiceNotice model;
        try {
            model = this.stopServiceNoticeRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        if (model != null) {
            dto.setId(model.getId());
        }
        model = this.stopServiceNoticeConventer.toModel(dto);

        this.stopServiceNoticeRepository.save(model);
        return this.stopServiceNoticeConventer.toDTO(model);
    }

    @Override
    public StopServiceNoticeDTO details(final Long id) {
        final StopServiceNotice model;
        try {
            model = this.stopServiceNoticeRepository.getById(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }
        return this.stopServiceNoticeConventer.toDTO(model, false);
    }

    @Override
    public void delete(final Long id) {
        this.stopServiceNoticeRepository.deleteById(id);
    }

    @Override
    public void resendMessage(final Long id) {
        final StopServiceNotice model;
        try {
            model = this.stopServiceNoticeRepository.getById(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        this.asyncSendMessage(model);
    }

    @Autowired
    private SendMessageExecutors sendMessageExecutors;

    @Component
    class SendMessageExecutors {
        @Value("${docm.stopServiceNotice.threadNum: 3}")
        private Integer threadNum;

        private ExecutorService executor;

        @PostConstruct
        public void init() {
            this.executor = Executors.newFixedThreadPool(this.threadNum);
        }

        @PreDestroy
        public void destroy() {
            this.executor.shutdown();
        }

        private void handler(final Callable<String> callback) {
            this.executor.submit(callback);
        }
    }

    private void asyncSendMessage(final StopServiceNotice model) {
        final Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                StopServiceNoticeServiceImpl.log.info("waiting send to users -> [" + model.getJsonUsers() + "]");
                final String cb = StopServiceNoticeServiceImpl.this.sendMessage(model);
                return cb;
            }
        };
        this.sendMessageExecutors.handler(callable);
    }

    /**
     * 发送消息
     */
    private String sendMessage(final StopServiceNotice model) {
        StopServiceNoticeServiceImpl.log.info("-----准备开始发送消息----- ");
        //拼消息体
        final JSONObject notice = new JSONObject();

        try {
            String objsStr = "";
            if (StringUtils.isNotEmpty(model.getJsonObjs())) {
                final List<CMDBInstanceDTO> iList = JSON.parseArray(model.getJsonObjs(), CMDBInstanceDTO.class);
                if (CollectionUtils.isNotEmpty(iList)) {
                    final List<String> nameList =
                            iList.stream().map(p -> p.getName() + "(" + p.getCode() + ")").collect(Collectors.toList());
                    objsStr = Joiner.on(DCOMConstants.COMMA_SPILT).join(nameList);
                }
            }

            final StringBuffer content = new StringBuffer(DCOMConstants.MAINTAIN_TASK_STOP_SERVICE_NOTICE);

            notice.put("appCode", "DCOM");
            notice.put("title", DCOMConstants.STOP_SERVICE_NOTICE);
            notice.put("type", Arrays.asList(model.getNoticeType().split(DCOMConstants.COMMA_SPILT)));

            final JSONObject system = new JSONObject();
            system.put("noticeType", DCOMConstants.STOP_SERVICE_NOTICE);

            system.put("noticeRoute", "");

            final JSONArray usernames = new JSONArray();
            if (StringUtils.isNotEmpty(model.getJsonUsers())) {
                final List<UserDTO> users = JSON.parseArray(model.getJsonUsers(), UserDTO.class);
                if (CollectionUtils.isNotEmpty(users)) {
                    users.stream().map(user -> usernames.add(user.getUsername())).collect(Collectors.toList());
                }
            }
            system.put("users", usernames);

            // 维护Content
            content.append(DCOMConstants.MAINTAIN_OBJECT).append(objsStr)
                    .append(DCOMConstants.MAINTAIN_RIGHT_MIDDLE_BRACKETS);
            content.append(DCOMConstants.MAINTAIN_DEPARTMENT).append(model.getOrgName())
                    .append(DCOMConstants.MAINTAIN_RIGHT_MIDDLE_BRACKETS);
            content.append(DCOMConstants.MAINTAIN_LOCATION).append(model.getLocation())
                    .append(DCOMConstants.MAINTAIN_RIGHT_MIDDLE_BRACKETS);

            final SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            content.append(DCOMConstants.STOP_SERVICE_TIME).append(dataFormat.format(model.getStopTime()))
                    .append(DCOMConstants.MAINTAIN_RIGHT_MIDDLE_BRACKETS);
            content.append(DCOMConstants.MAINTAIN_START_TIME).append(dataFormat.format(model.getStartDateTime()))
                    .append("] ");
            content.append(DCOMConstants.MAINTAIN_END_TIME).append(dataFormat.format(model.getEndDateTime()))
                    .append("] ");

            content.append(DCOMConstants.MAINTAIN_CONTENT).append(model.getContent())
                    .append(DCOMConstants.MAINTAIN_RIGHT_MIDDLE_BRACKETS);
            system.put("content", content.toString());

            notice.put("system", system);
            this.sendingMessage.SendMsgToNotice(notice.toString());

            StopServiceNoticeServiceImpl.log.info("-----发送的消息内容是： " + notice.toString());

            model.setStatus(StopServiceNoticeSendStatusEnum.send);
        } catch (final Exception e) {

            model.setStatus(StopServiceNoticeSendStatusEnum.unsend);
            e.printStackTrace();
        }
        // 更新发送状态
        this.stopServiceNoticeRepository.save(model);

        return notice.toString();
    }

    @Override
    public void discard(final Long id) {
        final StopServiceNotice model;
        try {
            model = this.stopServiceNoticeRepository.getById(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        model.setStatus(StopServiceNoticeSendStatusEnum.discard);
        this.stopServiceNoticeRepository.save(model);
    }

}
